<?php

class Mssql {
	const FETCH_ASSOC = 1;
	const FETCH_NUM = 2;
	const FETCH_BOTH = 3;
	const FETCH_OBJ = 4;
	
	protected $connection = null;
	protected $results;
	
	private static $instance =  null;
	
	public static function instance() {
		if (self::$instance === null) {
			self::$instance = new self();
		}
		return self::$instance;
	}
	
	public static function connect(array $settings) {
		$self = self::instance();
		$self->connection = mssql_connect($settings['host'], $settings['username'], $settings['password'], true);
		if (!mssql_select_db($settings['database'], $self->connection)) {
			throw new Exception('Unable to connect to the database');
		}
	}

	public static function disconnect() {
		$self = self::instance();
        if (mssql_close($self->connection)) {
            $self->connection = null;
        }
	}
	
	public static function enabled() {
		return extension_loaded('mssql');
	}
	
    public static function &connection() {
        return self::instance()->connection;
    }
	
    public static function query($sql = null, $params = array()) {
    	$self = self::instance();
       	if (!$self->results = mssql_query(self::prepare($sql, $params), self::connection())) {
       		throw new Exception(sprintf('Cloud be not execute query "%s"', self::prepare($sql, $params)));
       	}
        return $self->results;
    }
    
    public static function fetch($sql = null, $params = array(), $type = self::FETCH_OBJ) {
        $results = self::query($sql, $params);
		return self::fetch_row($results, $type);
    }

    public static function fetch_all($sql = null, $params = array(), $type = self::FETCH_OBJ) {
    	$results = self::query($sql, $params);
		$rows = array();
		while ($result = self::fetch_row($results, $type)) {
			$rows[] = $result;
		}
		return $rows;
    }

    public static function fetch_row($results = null, $type = self::FETCH_OBJ) {
    	switch ($type) {
    		case self::FETCH_ASSOC:
    			$mode = 'mssql_fetch_assoc';
    			break;
    		case self::FETCH_NUM:
    			$mode = 'mssql_fetch_row';
    			break;
    		case self::FETCH_BOTH:
    			$mode = 'mssql_fetch_array';
    			break;
    		default:
    			$mode = 'mssql_fetch_object';
    	}
        return $mode($results);
    }

	public static function last_insert_id() {
		$result = self::fetch('SELECT SCOPE_IDENTITY() AS insert_id');
		return $result->insert_id;
	}
	
	private static function prepare($sql = null, $params = array()) {
        if (!empty($params)) {
        	preg_match_all('/:(?P<name>\w+)\[(?P<type>\w+)\]/i', $sql, $match, PREG_SET_ORDER);
            $replace = array();
        	foreach ($match as $key => $value) {
            	$replace[$value[0]] = self::value($params[$value['name']], $value['type']);
            }
        	$sql = str_replace(array_keys($replace), array_values($replace), $sql);
        }
		return $sql;
	}

	private static function value($data, $type = null) {
		if ($data === null) {
			return 'NULL';
		}
		if (in_array($type, array('integer', 'float', 'binary')) && $data === '') {
			return 'NULL';
		}
		if ($data === '') {
			return "''";
		}
		switch ($type) {
			case 'boolean':
				$data = self::boolean((bool)$data);
			break;
			default:
				if (get_magic_quotes_gpc()) {
					$data = stripslashes(str_replace("'", "''", $data));
				} else {
					$data = str_replace("'", "''", $data);
				}
			break;
		}
		if (in_array($type, array('integer', 'float', 'binary')) && is_numeric($data)) {
			return $data;
		}
		return "'" . $data . "'";
    }
    
    private static function boolean($data) {
    	if ($data === true || $data === false) {
    		if ($data === true) {
    			return 1;
    		}
    		return 0;
    	} else {
    		return !empty($data);
    	}
    }
}

?>